﻿using System;
using System.Collections.Generic;
using TeamTasker.Contracts;
using TeamTasker.Server.DataAccess;
using TeamTasker.Utils;
using TeamTasker.Server.BusinessLogic.Format;
using System.Text;

namespace TeamTasker.Server.BusinessLogic
{
    public class TaskFacade : BaseFacade<Task, TaskDAO>
    {
        public PropertyFormatter Formatter { get; set; }

        public IList<Task> GetTaskList(long assignedUserID,
                                       DateTime start, DateTime end)
        {
            IList<Task> result = new List<Task>();
            IList<long> ids = Dao.GetTaskIDs(assignedUserID, start, end);
            foreach (long id in ids)
            {
                Task task = Load(id);
                result.Add(task);
            }
            return result; 
        }

        public override void Save(Task entity)
        {
            if (entity.ID == 0)
            {
                entity.CreationDate = DateTime.Now;
            }
            else
            {
                Validate.NotNull(Formatter, "Property formatter is not set");
                Task oldTask = Dao.LoadForCompare(entity.ID);
                Compare(entity, oldTask);
            }
            base.Save(entity);
        }

        public void AssignTask(long taskID, long userID, long managerID)
        {
            throw new NotImplementedException();
        }

        public void AddTaskComment(long taskID, string comment, long userID)
        {
            throw new NotImplementedException();
        }

        protected void Compare(Task newTask, Task oldTask)
        {
            Validate.NotNull(newTask, "Modified task instance is illegal: null");
            Validate.NotNull(oldTask, "Previous task instance is illegal: null");

            IList<TaskHistoryEntry> result = new List<TaskHistoryEntry>();

            result.Add(CompareProperty(newTask, oldTask, "Summary", PropertyType.String));
            result.Add(CompareProperty(newTask, oldTask, "Details", PropertyType.String));
            result.Add(CompareProperty(newTask, oldTask, "Estimation", PropertyType.Float));
            result.Add(CompareProperty(newTask, oldTask, "BaselineStartDate", PropertyType.Date));
            result.Add(CompareProperty(newTask, oldTask, "BaselineEndDate", PropertyType.Date));
            result.Add(CompareProperty(newTask, oldTask, "ActualStartDate", PropertyType.Date));
            result.Add(CompareProperty(newTask, oldTask, "ActualEndDate", PropertyType.Date));
            result.Add(CompareProperty(newTask, oldTask, "Priority", PropertyType.Enum));
            result.Add(CompareProperty(newTask, oldTask, "Status", PropertyType.Enum));
            result.Add(CompareProperty(newTask, oldTask, "ParentTaskName", PropertyType.String));
            result.Add(CompareProperty(newTask, oldTask, "AssignedUserName", PropertyType.String));
            result.Add(CompareProperty(newTask, oldTask, "UserAllocationPercentage", PropertyType.Int));

            string oldValue = FormatDictionaryValues(oldTask.Predecessors);
            string newValue = FormatDictionaryValues(newTask.Predecessors);
            result.Add(CompareValues(newValue, oldValue, "Predecessor task(s)", PropertyType.String));

            DateTime time = DateTime.Now;
            foreach (TaskHistoryEntry entry in result)
            {
                if (entry != null)
                {
                    entry.TaskID = newTask.ID;
                    entry.UserID = newTask.ModifiedBy;
                    entry.Date = time;
                    newTask.History.Add(entry);
                }
            }
        }

        protected TaskHistoryEntry CompareProperty(Task newTask,
                                                   Task oldTask,
                                                   string propName, 
                                                   PropertyType propType)
        {
            object newValue = ReflectionUtils.CallGetProperty(newTask, propName);
            object oldValue = ReflectionUtils.CallGetProperty(oldTask, propName);

            return CompareValues(newValue, oldValue, propName, propType);
        }

        protected TaskHistoryEntry CompareValues(object newValue,
                                                 object oldValue,
                                                 string propName,
                                                 PropertyType propType)
        {
            TaskHistoryEntry result = null;
            if ((newValue == null && oldValue == null)
                || (newValue != null && oldValue != null && newValue.Equals(oldValue)))
            {
                // 1.) was null, became null - no change
                // 2.) equal - no change
            }
            else if ((newValue == null && oldValue != null)
                    || (newValue != null && oldValue == null)
                    || (newValue != null && oldValue != null && !newValue.Equals(oldValue)))
            {
                result = new TaskHistoryEntry();
                result.FieldName = propName;
                result.OldValue = Formatter.ValueToString(oldValue, propType);
                result.NewValue = Formatter.ValueToString(newValue, propType);
            }

            return result;
        }

        protected string FormatDictionaryValues(IDictionary<long, string> dict)
        {
            Validate.NotNull(dict, "Dictionary is null");
            StringBuilder sb = new StringBuilder();
            foreach (string value in dict.Values)
            {
                sb.Append(value);
                sb.Append("; ");
            }
            if (sb.Length > 0)
            {
                sb.Length = sb.Length - 2; // cut last separator
            }
            return sb.ToString();
        }
    }
}
